package util

import enums.Role
import enums.EPState
import scala.collection.immutable.HashMap
import scala.collection.immutable.HashSet
import play.mvc.Action
import util.annotations.NamedAction
import play.mvc.Results
import play.api.cache.Cache
import services.ColegioSrv
import scala.util.Random
import models.TienePersona
import org.reflections.Reflections
import controllers.UserCtrl
import play.api.libs.json.Json
import play.api.libs.json.JsNull
import sanduche.controllers.UserController

class PermissionValidator() extends Action[NamedAction]() {

  def call(ctx: play.mvc.Http.Context): play.mvc.Result = {
    val maybeSessionJson = Option(ctx.session.get(UserController.SESSION_OBJ));
    maybeSessionJson.flatMap(sessionJson => {
      val path = ctx.request.path
      (if (path.startsWith("/api/coordinador/")) {
        Some(Role.COORDINADOR)
      } else if (path.startsWith("/api/profesor/")) {
        Some(Role.PROFESOR)
      } else {
        None;
      }).flatMap(role => {
        (Json.parse(sessionJson) \ (role.name.toLowerCase) \ "idColegio").asOpt[Long]
          .flatMap(idCol => {
            if (PermissionValidator.validate(ColegioSrv.getColegio(idCol).getState(), role, configuration.value()))
              None
            else
              Some(None)
          })
      }).getOrElse(Some(delegate.call(ctx)))

    }).getOrElse(Results.unauthorized("Esta acción no puede ser realizada"));
  }
}
object PermissionValidator {

  private val stateRoleAction: HashMap[EPState, HashMap[Role, HashSet[String]]] = HashMap(
    EPState.CONFIG_COLEGIO ->
      HashMap(
        Role.SUPADMIN
          -> HashSet("goNext", "newColegio", "updateGrado"),
        Role.COORDINADOR
          -> HashSet("read"),
        Role.PROFESOR -> HashSet("read"),
        Role.SECRETARIO -> HashSet("read")),
    EPState.CONFIG_PERIODO ->
      HashMap(
        Role.SUPADMIN
          -> HashSet("goNext", "newColegio", "updateGrado"),
        Role.COORDINADOR
          -> HashSet("goNext", "read", "newEstudiante",
            "updateCalendarioAcademico", "newCurso",
            "updateCurso", "deleteCurso", "updateMateriaCurso", "newSecretario", "newProfesor"),

        Role.PROFESOR -> HashSet(),
        Role.SECRETARIO -> HashSet()),
    EPState.MATRICULAS ->
      HashMap(
        Role.SUPADMIN
          -> HashSet("goNext", "newColegio", "updateGrado"),
        Role.COORDINADOR
          -> HashSet("goNext", "newEstudiante", "newCurso", "updateCurso",
            "read", "newMatricula", "newSecretario", "newProfesor"),
        Role.PROFESOR -> HashSet(),
        Role.SECRETARIO -> HashSet()),
    EPState.SUBIDA_NOTAS -> HashMap(
      Role.SUPADMIN -> HashSet("goNext", "updateGrado"),
      Role.COORDINADOR -> HashSet("goNext", "read", "newMatricula", "newEstudiante"),
      Role.PROFESOR -> HashSet("getMisAsignaturas", "read", "getIndicadores",
        "getIndicadoresEstudiantes", "newIndicador",
        "updateIndicador", "deleteIndicador", "newIndicadorEstudiante", "deleteIndicadorEstudiante", "setCalificacionPeriodo", "sendMessage"),
      Role.SECRETARIO -> HashSet()),
    EPState.CIERRE_CALENDARIO ->
      HashMap(
        Role.SUPADMIN
          -> HashSet("goNext", "newColegio", "updateGrado"),
        Role.COORDINADOR
          -> HashSet("goNext", "read"),
        Role.PROFESOR -> HashSet(),
        Role.SECRETARIO -> HashSet()));
  val permissionsMap = HashSet((for (
    (state, roleMap) <- stateRoleAction;
    (role, actionSet) <- roleMap;
    action <- actionSet
  ) yield (state, role, action)).toList: _*)
  val actionSet = permissionsMap.map(_._3);

  def validate(state: EPState, role: Role, action: String): Boolean = {
    if (!(actionSet contains action))
      throw new Exception("Error de configuracion. La accion " + action + " no existe")
    permissionsMap contains (state, role, action)
    //println("por favor cambiar esto para que haga validaciones reales, esto es solo para testing en desarrollo")
    //true
  }
  def generateUsername(ac: TienePersona): String = {

    ac.getPersona().getTipoDocumento().name() + ac.getPersona().getDocumento();

  }

  def generatePassword(ac: TienePersona): String = generateUsername(ac);

}

